package com.bottle.android_mvi.ui.view

import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberUpdatedState
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.bottle.android_mvi.domain.intent.IUIEffect
import com.bottle.android_mvi.domain.intent.IUiState
import com.bottle.android_mvi.domain.viewmodel.BaseMVIViewModel
import kotlinx.coroutines.withContext
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext


/**
 * 一个用于处理UI状态和副作用的组合式UI组件
 *
 * 此函数用于在Composable环境中构建UI，它不仅处理UI的状态，还处理与状态相关的副作用。
 * 通过绑定ViewModel，它可以响应状态变化并执行相应的副作用，比如UI效果或数据操作。
 *
 * @param viewModel ViewModel实例，用于管理UI状态和副作用
 * @param initialState 初始化的UI状态，可选参数
 * @param lifecycle 生命周期所有者，用于监听生命周期事件
 * @param minActiveState 组件在生命周期中的最小活跃状态，低于此状态组件将不处理状态更新
 * @param context 协程上下文，用于执行副作用操作
 * @param sideEffect 一个副作用函数，用于处理ViewModel产生的副作用事件
 * @param content Composable内容，用于展示UI状态
 */
@Composable
fun <S : IUiState, E : IUIEffect, VM : BaseMVIViewModel<*, S, E>> StateEffectScaffold(
    vm: VM,
    initialState: S? = null,
    lifecycle: Lifecycle = LocalLifecycleOwner.current.lifecycle,
    minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
    context: CoroutineContext = EmptyCoroutineContext,
    sideEffect: (suspend (VM, E) -> Unit)? = null,
    content: @Composable (VM, S) -> Unit
) {
    // 如果提供了副作用函数，则创建一个用于处理副作用的Lambda表达式
    sideEffect?.let {
        val lambdaEffect by rememberUpdatedState(sideEffect)
        // 在ViewModel的effect流上启动一个协程效果，并受生命周期控制
        LaunchedEffect(vm.effect, lifecycle, minActiveState) {
            // 当生命周期达到最小活跃状态时，重复监听ViewModel的effect流
            lifecycle.repeatOnLifecycle(minActiveState) {
                // 根据协程上下文，可能需要在特定的上下文中执行collect操作
                if (context == EmptyCoroutineContext) {
                    vm.effect.collect { lambdaEffect(vm, it) }
                } else withContext(context) {
                    vm.effect.collect { lambdaEffect(vm, it) }
                }
            }
        }
    }
    // collectAsStateWithLifecycle会在配置变更时首先回调initialState，因此必须传递最新的状态
    val uiState = vm.state.collectAsStateWithLifecycle(
        initialValue = vm.replayState,
        lifecycle = lifecycle,
        minActiveState = minActiveState,
        context = context
    )
    // 如果当前UI状态非空，则渲染Composable内容
    (uiState.value ?: initialState)?.let { content(vm, it) }
}